﻿
using PSL.ST;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PSL.Stack
{
    public class FunctionStack
    {
        #region Private Member
        private PSLRuntime engine;

        private IDictionary<string, Function> functions;
        #endregion

        #region Constructor
        /// <summary>
        /// Create PSL-Runtime
        /// </summary>
        /// <param name="Engine">PSL-Engine instance</param>
        public FunctionStack(PSLRuntime Engine)
        {
            engine = Engine;

            functions = new Dictionary<string, Function>();
        }
        #endregion

        #region Public Methods
        /// <summary>
        /// Call method
        /// </summary>
        /// <param name="FunctionName">Name of the function which should be called</param>
        /// <param name="Parameter">Parameter-Instance, which contains all different parameter</param>
        /// <returns>Return value form the called functiom</returns>
        internal dynamic Call(string FunctionName, object[] Parameter)
        {
            if (functions.ContainsKey(FunctionName))
            {
                Function function = functions[FunctionName];
                return function.Call(Parameter);
            }
            else
            {
                throw new Exception("The function " + FunctionName + " could not be found");
            }
        }

        /// <summary>
        /// Load functions which are in the SyntaxTree
        /// </summary>
        /// <param name="FunctionSyntaxTree">Instance of an syntax-tree</param>
        internal void LoadFunctions(SyntaxTree FunctionSyntaxTree)
        {
            foreach (DeclareFunctionNode node in FunctionSyntaxTree.RootNode.FindChildrenOfType<DeclareFunctionNode>())
            {
                if (!functions.ContainsKey(node.FunctionName))
                {
                    functions.Add(node.FunctionName, new Function(engine, node));
                }
                else
                {
                    throw new Exception("The function : " + node.FunctionName + " already exists.");
                }
            }
        }

        /// <summary>
        /// Add .net function
        /// </summary>
        /// <param name="FunctionName">Name of the functiom</param>
        /// <param name="Delegate">Delegate to the function</param>
        internal void AddFunction(string FunctionName, Delegate Delegate)
        {
            if (!functions.ContainsKey(FunctionName))
            {
                functions.Add(FunctionName, new Function(engine, FunctionName, Delegate));
            }
            else
            {
                throw new Exception("The function : " + FunctionName + " already exists.");
            }
        }
        #endregion
    }
}
